fix: resolve undefined {CANCEL_URL} in workflow templates#23476
fix: resolve undefined {CANCEL_URL} in workflow templates#23476anikdhabal merged 9 commits intocalcom:mainfrom
Conversation
|
@ShashwatPS is attempting to deploy a commit to the cal Team on Vercel. A member of the Team first needs to authorize it. |
WalkthroughAdds seatedBooking.uid into the calendarEvent payload passed to scheduleWorkflowReminders and switches the seatReferenceUid used when scheduling reminders from evt.attendeeSeatId to resultBooking?.seatReferenceUid in packages/features/bookings/lib/handleSeats/handleSeats.ts. In packages/features/ee/workflows/lib/reminders/emailReminderManager.ts, introduces an isEmailAttendeeAction flag to: include seatReferenceUid in cancel and reschedule URLs for attendee-targeted EMAIL_ATTENDEE actions and to select attendee locale for those emails. No public signatures were changed. Assessment against linked issues
Out-of-scope changes( none identified ) Possibly related PRs
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 💡 Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
Status, Documentation and Community
|
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/features/bookings/lib/handleSeats/handleSeats.ts(2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
packages/features/bookings/lib/handleSeats/handleSeats.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
packages/features/bookings/lib/handleSeats/handleSeats.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/features/bookings/lib/handleSeats/handleSeats.ts
🧬 Code graph analysis (1)
packages/features/bookings/lib/handleSeats/handleSeats.ts (1)
packages/features/ee/workflows/lib/reminders/reminderScheduler.ts (1)
scheduleWorkflowReminders(395-398)
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Install dependencies / Yarn install & cache
- GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (2)
packages/features/bookings/lib/handleSeats/handleSeats.ts (2)
132-132: Seat reference wiring depends on Line 111 fix.Passing
seatReferenceUid: currentAttendeeSeatIdis correct only if Line 111 sources it fromresultBooking?.seatReferenceUid. Please update Line 111 accordingly; otherwise reminders for later seats will still reference the wrong attendee.After the change, validate by booking 2 seats and inspecting each email/link target.
117-117: Prefer the updated booking UID for CANCEL_URL- uid: seatedBooking.uid, + uid: resultBooking?.uid ?? seatedBooking.uid,
|
@ShashwatPS pls check this and try to address it here:- #22572 (comment) |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (1)
163-166: URL-encode seatReferenceUid when appending to cancelLinkAvoid malformed links if the UID ever contains reserved characters.
Apply this minimal patch:
- }${seatReferenceUid ? `&seatReferenceUid=${seatReferenceUid}` : ""}`, + }${seatReferenceUid ? `&seatReferenceUid=${encodeURIComponent(seatReferenceUid)}` : ""}`,Optional: consider building these URLs with URL/URLSearchParams to remove string-concat edge cases.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Install dependencies / Yarn install & cache
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (1)
164-167: URL-encodeseatReferenceUidand prefer a params builder.
seatReferenceUidshould be encoded; also considerURLSearchParamsto keep both links robust and consistent.Minimal encoding tweak:
- }${isEmailAttendeeAction && seatReferenceUid ? `&seatReferenceUid=${seatReferenceUid}` : ""}`, + }${isEmailAttendeeAction && seatReferenceUid ? `&seatReferenceUid=${encodeURIComponent(seatReferenceUid)}` : ""}`,Cleaner alternative (add just above
const variables):const cancelUrl = new URL(`${bookerUrl}/booking/${evt.uid}`); cancelUrl.searchParams.set("cancel", "true"); if (recipientEmail) cancelUrl.searchParams.set("cancelledBy", recipientEmail); if (isEmailAttendeeAction && seatReferenceUid) cancelUrl.searchParams.set("seatReferenceUid", seatReferenceUid); const rescheduleUrl = new URL(`${bookerUrl}/reschedule/${evt.uid}`); if (recipientEmail) rescheduleUrl.searchParams.set("rescheduledBy", recipientEmail); if (isEmailAttendeeAction && seatReferenceUid) rescheduleUrl.searchParams.set("seatReferenceUid", seatReferenceUid);Then inside
variables:cancelLink: cancelUrl.toString(), rescheduleLink: rescheduleUrl.toString(),
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts(3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
🧠 Learnings (1)
📚 Learning: 2025-08-27T16:39:38.156Z
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-08-27T16:39:38.156Z
Learning: anglerfishlyy successfully implemented CAL-3076 email invitation feature for Cal.com team event-types in PR #23312. The feature allows inviting people via email directly from assignment flow, with automatic team invitation if email doesn't belong to existing team member. Implementation includes Host type modifications (userId?: number, email?: string, isPending?: boolean), CheckedTeamSelect component updates with CreatableSelect, TRPC schema validation with zod email validation, and integration with existing teamInvite system.
Applied to files:
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
🔇 Additional comments (2)
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (2)
143-143: Nice readability win withisEmailAttendeeAction.Clearer than repeating the comparison.
180-182: Align locale usage across template and custom-email flows
In emailReminderManager.ts the REMINDER/RATING template calls still use evt.organizer.language.locale while only the custom-body path switches to attendee.language?.locale. Confirm whether the default templates should also use the attendee’s locale for parity.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (3)
183-186: Use the selected attendee’s timezone consistentlyThese variables should reflect the timezone of
attendeeToBeUsedInMail(which may not beattendees[0]for EMAIL_ATTENDEE).- attendeeTimezone: evt.attendees[0].timeZone, - eventTimeInAttendeeTimezone: dayjs(startTime).tz(evt.attendees[0].timeZone), - eventEndTimeInAttendeeTimezone: dayjs(endTime).tz(evt.attendees[0].timeZone), + attendeeTimezone: attendeeToBeUsedInMail.timeZone, + eventTimeInAttendeeTimezone: dayjs(startTime).tz(attendeeToBeUsedInMail.timeZone), + eventEndTimeInAttendeeTimezone: dayjs(endTime).tz(attendeeToBeUsedInMail.timeZone),
419-431: Limit Prisma fetch to required fieldsOnly
uuidandreferenceIdare used; select them explicitly.- const workflowReminder = await prisma.workflowReminder.findUnique({ - where: - { id: reminderId }, - }); + const workflowReminder = await prisma.workflowReminder.findUnique({ + where: { id: reminderId }, + select: { uuid: true, referenceId: true }, + });
164-178: Optional: build links with URL/URLSearchParams to avoid ternariesConsider constructing both links with
URLSearchParamsto simplify branching and ensure encoding across all params.Example sketch (not a drop-in):
const cancel = new URL(`${bookerUrl}/booking/${evt.uid}`); const cancelQs = new URLSearchParams({ cancel: "true" }); if (recipientEmail) cancelQs.set("cancelledBy", recipientEmail); if (isEmailAttendeeAction && seatReferenceUid) cancelQs.set("seatReferenceUid", seatReferenceUid); const cancelLink = `${cancel.pathname}?${cancelQs.toString()}`; const res = new URL(`${bookerUrl}/reschedule/${evt.uid}`); const resQs = new URLSearchParams(); if (recipientEmail) resQs.set("rescheduledBy", recipientEmail); if (isEmailAttendeeAction && seatReferenceUid) resQs.set("seatReferenceUid", seatReferenceUid); const rescheduleLink = resQs.toString() ? `${res.pathname}?${resQs.toString()}` : res.pathname;
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts(3 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
**/*.ts: For Prisma queries, only select data you need; never useinclude, always useselect
Ensure thecredential.keyfield is never returned from tRPC endpoints or APIs
Files:
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/review.mdc)
Flag excessive Day.js use in performance-critical code; prefer native Date or Day.js
.utc()in hot paths like loops
Files:
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
**/*.{ts,tsx,js,jsx}
⚙️ CodeRabbit configuration file
Flag default exports and encourage named exports. Named exports provide better tree-shaking, easier refactoring, and clearer imports. Exempt main components like pages, layouts, and components that serve as the primary export of a module.
Files:
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
🧠 Learnings (1)
📚 Learning: 2025-08-27T16:39:38.156Z
Learnt from: anglerfishlyy
PR: calcom/cal.com#0
File: :0-0
Timestamp: 2025-08-27T16:39:38.156Z
Learning: anglerfishlyy successfully implemented CAL-3076 email invitation feature for Cal.com team event-types in PR #23312. The feature allows inviting people via email directly from assignment flow, with automatic team invitation if email doesn't belong to existing team member. Implementation includes Host type modifications (userId?: number, email?: string, isPending?: boolean), CheckedTeamSelect component updates with CreatableSelect, TRPC schema validation with zod email validation, and integration with existing teamInvite system.
Applied to files:
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts
⏰ Context from checks skipped due to timeout of 180000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (4)
packages/features/ee/workflows/lib/reminders/emailReminderManager.ts (4)
143-143: Good guard for attendee-specific behaviorUsing a single
isEmailAttendeeActionflag centralizes attendee-specific logic and reduces repeat conditionals. LGTM.
169-178: Reschedule link query-string fix looks correctNice job handling the leading “?” vs “&” and encoding
seatReferenceUid. This resolves the earlier edge case whererecipientEmailwas falsy.
298-311: Store seatReferenceId for SMTP/tasker-scheduled reminders as wellOther branches persist
seatReferenceId; this one doesn’t. For consistency and seat-scoped operations, persist it here too.if (scheduledDate) { const reminder = await prisma.workflowReminder.create({ data: { bookingUid: uid, workflowStepId, method: WorkflowMethods.EMAIL, scheduledDate: scheduledDate.toDate(), scheduled: true, + seatReferenceId: seatReferenceUid, }, });Would you confirm whether downstream consumers expect
seatReferenceIdfor SMTP-scheduled reminders?
188-190: Locale switch based on action is appropriateChoosing attendee locale for EMAIL_ATTENDEE and organizer otherwise is the right UX. LGTM.
E2E results are ready! |
What does this PR do?
When using the {CANCEL_URL} variable in the workflow for seated bookings, the scheduleWorkflowReminders function was called directly for the first seat, and the template worked fine. However, for subsequent seats, the handleSeats function (in packages/features/bookings/lib/handleSeats/handleSeats.ts), inside which scheduleWorkflowReminders was being called, did not pass the event’s uid. This uid was required to construct the cancel URL.
While fixing this, I also discovered that seatReferenceUid was being set incorrectly and fixed that as well.
Visual Demo
A booking with 2 seats


Mandatory Tasks (DO NOT REMOVE)
Files Modified
packages/features/bookings/lib/handleSeats/handleSeats.ts
How should this be tested?
Checklist